# -*- makefile -*-
V = 0
V0 = $(V:0=)
Q1 = $(V:1=)
Q = $(Q1:0=@)
ECHO1 = $(V:1=@:)
ECHO = $(ECHO1:0=@echo)
<%
require './rbconfig'
macros = {}
deps = []
notes = {}
rubies = []
exeext = RbConfig::CONFIG['EXEEXT']
gnumake = false
confexts = nil
opt = OptionParser.new do |o|
  o.on('--gnumake=BOOL') {|v| gnumake = v == 'yes'}
  o.on('--configure-exts=FILE') {|v| confexts = v}
  o.order!(ARGV)
end
confexts &&= File.read(confexts).scan(/^(?:ext|gem)s: (.*\.mk)/).flatten rescue nil
confexts ||= []
macros["old_extensions"] = []
distclean = []

contpat = /(?>(?>[^\\\n]|\\.)*\\\n)*(?>[^\\\n]|\\.)*/
Dir.glob("{ext,.bundle/gems}/*/exts.mk") do |e|
  gem = e.start_with?(".bundle/gems/")
  dir = File.dirname(e)
  s = File.read(e)
  s.scan(/^(extensions|SUBMAKEOPTS|EXT[A-Z]+|MFLAGS|MESSAGE_(?:BEGIN|END)|NOTE_[A-Z]+)[ \t]*=[ \t]*(#{contpat})$/o) do |n, v|
    v.gsub!(/\\\n[ \t]*/, ' ')
    if v.empty?
      distclean << dir if n == "extensions"
      next
    end
    n = "old_extensions" if n == "extensions" and !confexts.include?(e)
    v = v.split
    m = macros[n] ||= []
    case n
    when "LIBS"
      m.concat(v)
    else
      macros[n] = m | v
    end
    break if n == "old_extensions"
  end
  if gem
    r = ""
  else
    r = s[/^all static: (.+)$/, 1]
    deps << $&
    rubies |= r.split if r
    r = "(?:#{Regexp.new(r)})|"
  end
  s.scan(%r"^(ext/\S+)/[^/\s:]+:[ \t]*\1/static$|
            ^(?:#{r}
              all|static|install(?:-(?:so|rb))?|
              (?:dist|real)?clean
             ):.+$
           "x) do
    deps << $&.sub(/ +note$/, '')
  end
  s.scan(%r"^(note(?:-\w+)?):(:)?[ \t]*(#{contpat})\n((?:\t.+\n)*)"o) do |(t, m, d, n)|
    note = (notes[t] ||= [[m||""], []])
    note[0] |= d.split(/(?:\\\n|[ \t])[ \t]*/)
    n = n.split(/^/)
    if m
      note[1].concat(n)
    else
      note[1] |= n
    end
  end
end
deps.uniq!
macros["cleandirs"] = distclean.map {|d| "#{d}/."}
deps.map! {|d|
  /\A(?:dist|real)?clean(?=:)/ =~ d ? d + " $(cleandirs:/.=/#{$&})" : d
}

# NOTE: Only if extensions are configured as static and dynamic heterogeneously
# (e.g. --with-static-linked-ext=foo or ext/Setup can mix static and dynamic
# extensions), EXTOBJS may contain both extinit.o and dmyext.o. In such case,
# prefer extinit.o, which does actual Init_${ext} function calls for statically
# linked extensions, and drop dmyext.o, which does nothing but just to make the
# linker happy.
if objs = macros["EXTOBJS"] and objs.any? {|e|e.start_with?("ext/extinit.")}
  objs.delete_if {|e|e.start_with?("dmyext.")}
end
macros.default = [].freeze
class Array
  def fold(h, w = 70)
    return "" if empty?
    w -= h
    ret = [s = String.new]
    each do |e|
      if s.size + e.size + 1 > w
        ret << (s = String.new)
      end
      s << " " << e
    end
    ret.join(" \\\n" + "\t" * (h / 8) + " " * (h % 8))
  end
end
@erbout = _erbout
def self.column
  w = 0
  @erbout[/^.*\z/].scan(/\t|([^\t]+)/) {|s,| w += (s ? s.size : 8 - w % 8)}
  w
end
objext = RbConfig::CONFIG["OBJEXT"]
sep = RbConfig::CONFIG['BUILD_FILE_SEPARATOR']
sep = nil if sep and sep.empty?
if gnumake
  submake = "$(MAKE) -C $(@D)"
else
  submake = ["cd", (sep ? "$(@D:/=#{sep})" : "$(@D)"), "&&"]
  exec = RbConfig::CONFIG["exec"] and !exec.empty? and submake << exec
  submake = (submake << "$(MAKE)").join(" ")
  mflags = " $(MFLAGS)"
end
-%>
% macros.each_pair do |k, v|
<%=k%> =<%= v.fold(column) %>
% end
% RbConfig::MAKEFILE_CONFIG.keys.grep(/RM/) do |k|
<%=k%> = <%=RbConfig::MAKEFILE_CONFIG[k]%>
% end

all:
static:

clean:
	-$(Q)$(RM) ext/extinit.<%= objext %>
distclean:
	-$(Q)$(RM) ext/extinit.c

% deps.each do |d|
<%= d %>
% end

% rubies.each do |ruby|
<%= ruby %>:
	$(Q)$(MAKE)<%=mflags%> $(SUBMAKEOPTS) $@
% end
% if rubies.size > 1
<%= rubies[1..-1].join(' ')%>: <%= rubies[0] %>
% end

libencs:
	$(Q)$(MAKE)<%=mflags%> -f enc.mk V=$(V) MINIRUBY="$(MINIRUBY)" $@
ext/extinit.<%=objext%>:
	$(Q)$(MAKE)<%=mflags%> V=$(V) EXTINITS="$(EXTINITS)" $@

% exts = (macros["extensions"] + macros["old_extensions"])
% exts.map! {|e|e.chomp("/.")}.sort
% %w[all static install install-so install-rb].each do |tgt|
%   exts.each do |d|
%     pext = File.dirname(d)
<%=d%>/<%=tgt%>:<% if exts.include?(pext) %> <%=pext%>/<%=tgt%><% end %>
	$(Q)<%= submake %><%=mflags%> V=$(V) $(@F)
%   end
% end
% distclean = exts | distclean
% %w[clean distclean realclean].each do |tgt|
%   distclean.each do |d|
%     deps = exts.select {|e|e.start_with?("#{d}/")}.map {|e|"#{e}/#{tgt}"}
<%=d%>/<%=tgt%>:<% unless deps.empty? %> <%=deps.join(' ')%><% end %>
%     unless tgt == "clean"
	$(ECHO) $(@F)ing $(@D)
%     end
%     if exts.include?(d)
	$(Q)<%= submake %><%=mflags%> V=$(V) $(@F)
%     end
%     unless tgt == "clean"
	$(Q)$(RM) <%=d[%r[\A(?:\.[^/]+/)?(?:[^/]+/)?[^/]+]]%>/exts.mk
	-$(Q)$(RMDIRS) $(@D)
%     end
%   end
% end

extso:
	@echo EXTSO=$(EXTSO)

% notes.each_pair do |k, (d, n)|
<%= k %>:<%= d.join(' ') %>
<%= n.join("") %>
% end

remove-old-extensions: $(old_extensions:/.=/distclean)
